package com.ctw.mapmycity.auth;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import org.apache.http.protocol.HTTP;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.ctw.mapmycity.Constants;
import com.ctw.mapmycity.R;
import com.ctw.mapmycity.RegisterActivity;
import com.ctw.mapmycity.client.RequestMethod;
import com.ctw.mapmycity.client.RestClient;
import com.ctw.mapmycity.util.MaskUtil;
import com.facebook.FacebookException;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.facebook.model.GraphUser;
import com.facebook.widget.LoginButton;
import com.facebook.widget.LoginButton.OnErrorListener;
import com.google.gson.Gson;

/**
 * Activity which displays a login screen to the user, offering registration as
 * well.
 */
public class LoginActivity extends Activity  {

	public static final String ARG_ACCOUNT_EMAIL = "mEmail";

	private UiLifecycleHelper uiHelper;

	/** Keep track of the login task so can cancel it if requested */
	private UserLoginTask mAuthTask = null;

	private AccountManager mAccountManager;

	// Values for email and password at the time of the login attempt.
	private String mEmail;
	private String mPassword;

	// UI references.
	private EditText mEmailView;
	private EditText mPasswordView;

	// Progress manager
	private MaskUtil maskUtil;
	private View mLoginFormView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_login);

		final Intent intent = getIntent();

		maskUtil = new MaskUtil(this);
		mLoginFormView = findViewById(R.id.login_form);

		mEmail = intent.getStringExtra(ARG_ACCOUNT_EMAIL);

		// Set up the login form.
		mEmailView = (EditText) findViewById(R.id.email);
		//mEmailView.setText(mEmail);

		mPasswordView = (EditText) findViewById(R.id.password);
		mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
			@Override
			public boolean onEditorAction(TextView textView, int id,
					KeyEvent keyEvent) {
				if (id == R.id.login || id == EditorInfo.IME_NULL) {
					attemptLogin();
					return true;
				}
				return false;
			}
		});

		findViewById(R.id.btnLogin).setOnClickListener(
				new View.OnClickListener() {
					@Override
					public void onClick(View view) {
						attemptLogin();
					}
				});

		final LoginButton authButton = (LoginButton) findViewById(R.id.fbLogin);
		authButton.setOnErrorListener(new OnErrorListener() {

			@Override
			public void onError(FacebookException error) {
				Log.i("LoginActivity", "Error " + error.getMessage());
			}
		});

		// set permission list, Don't foeget to add email
		authButton.setReadPermissions(Arrays.asList("basic_info", "email"));
		// session state call back event

		//		authButton.setSessionStatusCallback();

		TextView textheaderlogin = (TextView) findViewById(R.id.textheaderlogin);
		Typeface textheaderloginface = Typeface.createFromAsset(getAssets(), "fonts/AgentOrange.ttf");
		textheaderlogin.setTypeface(textheaderloginface);

		TextView registerScreen = (TextView) findViewById(R.id.link_to_register);
		// Listening to register new account link
		registerScreen.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				// Switching to Register screen or Goto Menu
				Intent i = new Intent(getApplicationContext(), RegisterActivity.class);
				startActivity(i);
			}
		});

		printHashKey();

		if (intent.getIntExtra(AccountManager.KEY_ERROR_CODE, -1) == AccountManager.ERROR_CODE_NETWORK_ERROR){
			maskUtil.mask(mLoginFormView, -1);
		}

		uiHelper = new UiLifecycleHelper(this, new Session.StatusCallback() {

			@Override
			public void call(Session session, SessionState state, Exception exception) {
				if (session.isClosed() || !session.isOpened())
					return;

				maskUtil.mask(mLoginFormView, R.string.login_progress_signing_in);

				Log.i("LoginActivity","Access Token"+ session.getAccessToken());				

				Request fbSyncReq = Request.newMeRequest(session, new Request.GraphUserCallback() {
					@Override
					public void onCompleted(GraphUser user, Response response) {
						maskUtil.unmask(mLoginFormView);

						if (user != null) {
							final Bundle result = new Bundle();
							result.putString(AccountManager.KEY_ACCOUNT_NAME, user.getProperty("email").toString());
							result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
							result.putString(AccountManager.KEY_AUTHTOKEN, Session.getActiveSession().getAccessToken());
							result.putString(AccountManager.KEY_AUTHENTICATOR_TYPES, LoginType.FB.getType());

							authButton.setSessionStatusCallback(null);

							new AsyncTask<com.ctw.mapmycity.model.Account, Void, com.ctw.mapmycity.model.Account>() {
								@Override
								protected com.ctw.mapmycity.model.Account doInBackground(com.ctw.mapmycity.model.Account... account) {
									com.ctw.mapmycity.model.Account acc = account[0];
									Gson gson = new Gson();
									try {
										RestClient client = null;
										client = new RestClient("/account");
										client.AddHeader("Accept", "application/json");
										client.AddHeader(HTTP.CONTENT_TYPE, "application/json");
										client.AddParam("account", gson.toJsonTree(acc).toString());

										client.Execute(RequestMethod.POST);
										String response = client.getResponse();
										acc = gson.fromJson(response, com.ctw.mapmycity.model.Account.class);
									} catch (Exception e) {
										acc = null;
									}
									return acc;
								}

								@Override
								protected void onPostExecute(final com.ctw.mapmycity.model.Account acc) {
									finishLogin(result);
									authButton.setSessionStatusCallback(null);
								}

							}.execute(new com.ctw.mapmycity.model.Account(
									user.getProperty("email").toString(), 
									user.getFirstName() + " " + user.getLastName(), 
									"", "",
									LoginType.FB.getType()));

						}else {
							CharSequence text = "Could not Connect to FB.";
							int duration = Toast.LENGTH_SHORT;
							Toast toast = Toast.makeText(getApplicationContext(), text, duration);
							toast.show();
						}
					}
				});
				fbSyncReq.executeAsync();
			} 
		});
		uiHelper.onCreate(savedInstanceState);
	}

	protected void onResume() {
		super.onResume();
		uiHelper.onResume();
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		uiHelper.onPause();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		uiHelper.onDestroy();
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		super.onActivityResult(requestCode, resultCode, data);
		uiHelper.onActivityResult(requestCode, resultCode, data);
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		uiHelper.onSaveInstanceState(outState);
	}
	
	@Override
	protected void onStop() {
		super.onStop();
	}

	@Override
	public void onBackPressed() {
		this.moveTaskToBack(true);
		finish();
	}

	public void printHashKey() {

		try {
			PackageInfo info = getPackageManager().getPackageInfo("com.ctw.mapmycity", PackageManager.GET_SIGNATURES);
			for (Signature signature : info.signatures) {
				MessageDigest md = MessageDigest.getInstance("SHA");
				md.update(signature.toByteArray());
				String key = Base64.encodeToString(md.digest(), Base64.DEFAULT);
				Log.d("TEMPTAGHASH KEY:", key);
			}
		} catch (NameNotFoundException e) {
			Log.i("LoginActivity", "Error " + e.getMessage());
		} catch (NoSuchAlgorithmException e) {

		}

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		getMenuInflater().inflate(R.menu.login, menu);
		return true;
	}

	/**
	 * Attempts to sign in or register the account specified by the login form.
	 * If there are form errors (invalid email, missing fields, etc.), the
	 * errors are presented and no actual login attempt is made.
	 */
	public void attemptLogin() {

		// Reset errors.
		mEmailView.setError(null);
		mPasswordView.setError(null);

		// Store values at the time of the login attempt.
		mEmail = mEmailView.getText().toString();
		mPassword = mPasswordView.getText().toString();

		boolean cancel = false;
		View focusView = null;

		// Check for a valid password.
		if (TextUtils.isEmpty(mPassword)) {
			mPasswordView.setError(getString(R.string.error_field_required));
			focusView = mPasswordView;
			cancel = true;
		} else if (mPassword.length() < 1) {
			mPasswordView.setError(getString(R.string.error_invalid_password));
			focusView = mPasswordView;
			cancel = true;
		}

		// Check for a valid email address.
		if (TextUtils.isEmpty(mEmail)) {
			mEmailView.setError(getString(R.string.error_field_required));
			focusView = mEmailView;
			cancel = true;
		} else if (!mEmail.contains("@")) {
			mEmailView.setError(getString(R.string.error_invalid_email));
			focusView = mEmailView;
			cancel = true;
		}

		if (cancel) {

			focusView.requestFocus();
		} else {

			mAuthTask = new UserLoginTask();
			mAuthTask.execute();
		}

	}

	/**
	 * Represents an asynchronous task used to authenticate a user against the
	 * SampleSync Service
	 */
	public class UserLoginTask extends AsyncTask<Void, Void, Bundle> {
		@Override
		protected void onPreExecute() {
			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
			if (imm.isActive())
				imm.hideSoftInputFromWindow(LoginActivity.this.getCurrentFocus().getWindowToken(), 0);

			maskUtil.mask(mLoginFormView, R.string.login_progress_signing_in);
		}

		@Override
		protected Bundle doInBackground(Void... params) {
			return new AuthenticatorUtil(LoginActivity.this.getApplication().getApplicationContext()).callAuthService(mEmail, mPassword);
		}

		@Override
		protected void onPostExecute(final Bundle result) {
			onAuthenticationResult(result);
		}

		@Override
		protected void onCancelled() {
			onFinallyExec();
		}

		/**
		 * Called when the authentication process completes (see attemptLogin()).
		 *
		 * @param resp the authentication token returned by the server, or NULL if
		 *            authentication failed.
		 */
		private void onAuthenticationResult(Bundle result) {
			onFinallyExec();

			String token = result.getString(AccountManager.KEY_AUTHTOKEN);

			if (token != null && !TextUtils.isEmpty(token)) {

				finishLogin(result);

			} else {

				Context context = LoginActivity.this.getApplicationContext();
				int duration = Toast.LENGTH_LONG;
				String errorMsg = "";

				int errorCode = result.getInt(AccountManager.KEY_ERROR_CODE);
				switch (errorCode) {
				case AccountManager.ERROR_CODE_NETWORK_ERROR:
					errorMsg = "No Internet Connection";
					break;
				default:
					errorMsg = "Invalid Email and Password";
					break;
				}

				Toast toast = Toast.makeText(context, errorMsg, duration);
				toast.show();
			}

		}

		private void onFinallyExec() {
			// Our task is complete, so clear it out
			mAuthTask = null;

			// Hide the progress dialog
			maskUtil.unmask(mLoginFormView);
		}
	}

	private void finishLogin(Bundle result) {

		final Account account = new Account(
				result.getString(AccountManager.KEY_ACCOUNT_NAME), Constants.ACCOUNT_TYPE);

		mAccountManager = AccountManager.get(getApplicationContext());
		for (Account acc : mAccountManager.getAccountsByType(Constants.ACCOUNT_TYPE)) {
			mAccountManager.removeAccount(acc, null, null);
		}

		Bundle userData = new Bundle();
		LoginType loginType = LoginType.getTypeEnum(result.getString(AccountManager.KEY_AUTHENTICATOR_TYPES));
		userData.putString(Authenticator.ACC_USER_DATA_AUTH_TYPE, 
				loginType != null ? loginType.getType() : LoginType.STANDARD.getType());

		mAccountManager.addAccountExplicitly(account, result.getString(AccountManager.KEY_AUTHTOKEN), userData);

		finish();
	}
}